package com.hfzy.ihk.web.aliyuncall.support.cloudcall.handler.doublecall;


import com.alibaba.fastjson.JSONObject;
import com.hfzy.ihk.common.util.date.DateUtils;
import com.hfzy.ihk.common.util.string.StringTools;
import com.hfzy.ihk.facade.aliyuncall.vo.CallHistory;
import com.hfzy.ihk.web.aliyuncall.biz.PushDataToBLBiz;
import com.hfzy.ihk.web.aliyuncall.biz.PushDataToEsBiz;
import com.hfzy.ihk.web.aliyuncall.constant.*;
import com.hfzy.ihk.web.aliyuncall.support.cloudcall.base.AbstractCallStateHandler;
import com.hfzy.ihk.web.aliyuncall.support.cloudcall.event.AliyunCallStateEvent;
import com.hfzy.ihk.web.aliyuncall.support.websocket.WebSocketUtils;
import com.hfzy.ihk.web.aliyuncall.vo.AliyunCallState;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.core.task.TaskExecutor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 阿里云呼入处理类
 */
@Component
@Scope("prototype")
public class AliyunCallStateHandler extends AbstractCallStateHandler<AliyunCallState,AliyunCallStateEvent> {

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    WebSocketUtils webSocketUtils;

    @Resource
    TaskExecutor pushDataToEsTaskExecutor;

    @Autowired
    PushDataToEsBiz pushDataToEsBiz;

    @Autowired
    PushDataToBLBiz pushDataToBLBiz;

    Logger logger = LoggerFactory.getLogger(AliyunCallStateHandler.class);
    public AliyunCallStateHandler() {
    }




    @Override
    protected Map<String, CallHistory> getMemoryCache() {
        return null;
    }

    /**
     * 读取redis
     * @param sessionId
     * @return
     */
    @Override
    protected Map<String, String> readRedis(String sessionId) {

        logger.debug("CallStateTaobaoWorkHandler readRedis："+sessionId);

        return  redisTemplate.opsForHash().entries(RedisKey.CALL_HISTORY_RPIX+sessionId);


    }



    @Override
    protected String handleReadRedisFailed(AliyunCallState Data) {
        return null;
    }

    /**
     * 将呼叫记录写入redis
     * @param sessionId
     * @param map
     * @return
     */
    @Override
    protected String writeRedis(String sessionId, Map<String, String> map) {
        if(map.isEmpty()) {
            logger.debug("writeRedis --->map is Empty,");
            return Constants.FAIL;
        }

        if("1".equals(map.get(RedisFields.CALL_HISTORY_CALL_TYPE)) || "2".equals(map.get(RedisFields.CALL_HISTORY_CALL_TYPE))) {
            redisTemplate.opsForHash().putAll(RedisKey.CALL_HISTORY_RPIX + sessionId, map);
            //超时时间三天
            redisTemplate.expire(RedisKey.CALL_HISTORY_RPIX + sessionId, RedisTimeOut.CACHE_THREE_DAY, TimeUnit.SECONDS);
        } else {
            redisTemplate.opsForHash().putAll(RedisKey.CALL_HISTORY_RPIX + sessionId, map);
        }
        return Constants.SUCCESS;
    }

    @Override
    protected String handleWriteRedisFailed(String sessionId, Map<String, String> map) {
        return null;
    }

    /**
     * 检查是否需要将记录推送到ES
     * @param callHistoryMap
     * @param redisMap
     * @param data
     * @return
     */
    @Override
    protected boolean checkCanOrNotPushToBatchInsertQueue(Map<String, String> callHistoryMap, Map<String, String> redisMap,AliyunCallState data) {
        boolean ableInsert = false;
        if (data.getMsgType().equals(AliyunAkInfo.VOICEREPORT)) {
            ableInsert = true;
        }
        return ableInsert;
    }


    @Override
    protected void handlePushStateToClientFail() {
        logger.info("handlePushStateToClientFail ....CallState");


    }


    /**
     * 分析呼入状态
     * @param callState
     * @param callHistoryMap
     * @return
     * @throws Exception
     */
    @Override
    protected Map<String, Map<String, String>> analyzeCallState(AliyunCallState callState, Map<String, String> callHistoryMap) throws Exception {

        Map<String,Map<String,String>> resultMap = new HashMap<>(2);
        //返回给客户端的map
        Map<String,String> msgMap = new HashMap<>(2);
        Map<String,String> redisSaveMap = new HashMap<>();

        logger.debug("analyze callState:" + callState.toString());
        String  nowDateStr = DateUtils.formatDate(new Date(), DateUtils.DATE_FORMAT_DATETIME_SSS);

        if(callState.getMsgType().equals(AliyunAkInfo.VOICECALLREPORT)){ //呼出中间状态
            switch (callState.getStatus_code()){
                case MsgStatus._200101:  //正在接通主叫 --当做提交成功 该状态不用推送给客户端
                    try {
                        //用于设定当前使用用户是否占线
                        if(callHistoryMap.get(RedisFields.CREATE_USER_ID)!=null) {
                            redisTemplate.opsForHash().put(RedisKey.USER_BUSY, callHistoryMap.get(RedisFields.CREATE_USER_ID), Constants.TRUE);
                        }
                    }catch (Exception e){
                        logger.error("======>call state：{} ",callState.getStatus_code(),e);
                    }

                    msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_INVALID);
                    break;
                case MsgStatus._200201:  //主叫响铃 该状态不用推送给客户端
                    redisSaveMap.put(RedisFields.CALL_HISTORY_MAIN_CALL_RINGING_TIME,  DateUtils.stringFromString(callState.getStatus_time(),DateUtils.DATE_FORMAT_DATETIME_SSS));
                    redisSaveMap.put(RedisFields.CALL_HISTORY_MAIN_CALL_RINGING, Constants.TRUE);
                    redisSaveMap.put(RedisFields.RECEIVE_CALL_HISTORY_MAIN_CALL_RINGING_TIME, nowDateStr);
                    msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_INVALID);
                    break;

                case MsgStatus._200202:  //被叫响铃 该状态不用推送给客户端
                    redisSaveMap.put(RedisFields.CALL_HISTORY_TARGET_CALL_RINGING_TIME,  DateUtils.stringFromString(callState.getStatus_time(),DateUtils.DATE_FORMAT_DATETIME_SSS));
                    redisSaveMap.put(RedisFields.CALL_HISTORY_TARGET_CALL_RINGING, Constants.TRUE);
                    redisSaveMap.put(RedisFields.RECEIVE_CALL_HISTORY_TARGET_CALL_RINGING_TIME, nowDateStr);
                    msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_INVALID);
                    break;

                case MsgStatus._200102:   ////正在接通被叫 ---当做主叫接通和被叫响铃时间

                    msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_MAIN_ANSWERED);

                    redisSaveMap.put(RedisFields.CALL_HISTORY_MAIN_CALL_ANSWERED, Constants.TRUE);
                    redisSaveMap.put(RedisFields.CALL_HISTORY_MAIN_CALL_ANSWERED_TIME, DateUtils.stringFromString(callState.getStatus_time(),DateUtils.DATE_FORMAT_DATETIME_SSS));
                    redisSaveMap.put(RedisFields.RECEIVE_HISTORY_MAIN_CALL_ANSWERED_TIME,nowDateStr);


                    break;

                case MsgStatus._200103:  //呼叫建立，正在通话(被叫应答)
                    msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_TARGET_ANSWERED);

                    redisSaveMap.put(RedisFields.CALL_HISTORY_TARGET_CALL_ANSWERED, Constants.TRUE);
                    redisSaveMap.put(RedisFields.CALL_HISTORY_TARGET_CALL_ANSWERED_TIME, DateUtils.stringFromString(callState.getStatus_time(), DateUtils.DATE_FORMAT_DATETIME_SSS));
                    redisSaveMap.put(RedisFields.RECEIVE_CALL_HISTORY_TARGET_CALL_ANSWERED_TIME, nowDateStr);

                    break;

                case MsgStatus._200100:   //呼叫结束（双呼） 返回的呼叫状态
                    //客户不接->客户无接听
                    //客户接，经纪还没接，客户就挂断->客户挂机
                    //客户接、经纪接->结束通话
                    try {
                        if (callHistoryMap.get(RedisFields.CALL_HISTORY_DISCONNECT_TIME) == null) { //由于会发多次，取第一次和账单那次就好，呼入账单状态回来就入库和推置业


                            //通话结束状态回来以后将该使用用户的繁忙状态改为否
                            if (callHistoryMap.get(RedisFields.CREATE_USER_ID) != null) {
                                redisTemplate.opsForHash().put(RedisKey.USER_BUSY, callHistoryMap.get(RedisFields.CREATE_USER_ID), Constants.FALSE);
                            }
                            redisSaveMap.put(RedisFields.CALL_HISTORY_DISCONNECT_TIME, DateUtils.stringFromString(callState.getStatus_time(), DateUtils.DATE_FORMAT_DATETIME_SSS));
                            redisSaveMap.put(RedisFields.RECEIVE_CALL_HISTORY_DISCONNECT_TIME, nowDateStr);

                            if (!Constants.TRUE.equals(callHistoryMap.get(RedisFields.CALL_HISTORY_MAIN_CALL_ANSWERED))) { //呼叫主叫失败，（各种原因）

                                msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_MAIN_FAILED);
                                msgMap.put(Constants.WEB_SOCKET_JSON_KEY_DESC, Constants.FJ_TELECOM_FAILED_REASON_MAIN_FAILED_4);

                                redisSaveMap.put(RedisFields.CALL_HISTORY_MAIN_CALL_FAILED, Constants.TRUE);
                                redisSaveMap.put(RedisFields.CALL_HISTORY_MAIN_CALL_FAILED_TIME, DateUtils.stringFromString(callState.getStatus_time(), DateUtils.DATE_FORMAT_DATETIME_SSS));
                                redisSaveMap.put(RedisFields.RECEIVE_CALL_HISTORY_MAIN_CALL_FAILED_TIME, nowDateStr);

                            } else if (!Constants.TRUE.equals(callHistoryMap.get(RedisFields.CALL_HISTORY_TARGET_CALL_ANSWERED))) { //呼叫被叫失败（各种原因）

                                msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_TARGET_FAILED);
                                msgMap.put(Constants.WEB_SOCKET_JSON_KEY_DESC, Constants.FJ_TELECOM_FAILED_REASON_MAIN_FAILED_5);

                                redisSaveMap.put(RedisFields.CALL_HISTORY_TARGET_CALL_FAILED, Constants.TRUE);
                                redisSaveMap.put(RedisFields.CALL_HISTORY_TARGET_CALL_FAILED_TIME, DateUtils.stringFromString(callState.getStatus_time(), DateUtils.DATE_FORMAT_DATETIME_SSS));
                                redisSaveMap.put(RedisFields.RECEIVE_CALL_HISTORY_TARGET_CALL_FAILED_TIME, nowDateStr);

                            } else { //正常通话结束
                                msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_TARGET_DISCONNECTED);

                            }

                        } else { //多余的状态不推送到客户端
                            msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_INVALID);

                        }
                    }catch (Exception e){ //防止话单比结束状态早回来的情况
                        msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_TARGET_DISCONNECTED);
                    }

                    break;
                default: //多余状态不推送到客户端
                    msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_INVALID);
                    break;

            }

            if(!Constants.CALL_OUT.toString().equals(callHistoryMap.get(RedisFields.CALL_HISTORY_CALL_TYPE))){ //呼入状态不返回客户端
                msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_INVALID);
            }

            //如果中断，后续的数据不发送到客户端
            if(redisTemplate.opsForValue().get(RedisKey.INTERRUPT_FAIL+callHistoryMap.get(RedisFields.CALL_HISTORY_SESSION_ID)) != null){

                redisSaveMap.put(RedisFields.CALL_HISTORY_REMARK,Constants.LOCAL_MSG_CALL_CANCEL);
                msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_INVALID);
            }

        }else if(callState.getMsgType().equals(AliyunAkInfo.VOICEREPORT)){//呼出话务单话务单回来之后才推送给持久化服务


            //呼出话单处理
            if(Constants.CALL_OUT.toString().equals(callHistoryMap.get(RedisFields.CALL_HISTORY_CALL_TYPE))){         //处理呼出话单，

                String statusCode = callState.getStatus_code();
                String statusMsg = callState.getStatus_msg();
                if(statusMsg!=null) {
                    redisSaveMap.put(RedisFields.CALL_HISTORY_REMARK, statusMsg);
                }
                //手动取消外呼显示取消外呼
                logger.info("aliyun------------------INTERRUPT：{}",callHistoryMap.get(RedisFields.INTERRUPT));

                if(callHistoryMap.get(RedisFields.INTERRUPT)!=null
                        &&Constants.INTERRUPT.toString().equals(callHistoryMap.get(RedisFields.INTERRUPT))){
                    redisSaveMap.put(RedisFields.CALL_HISTORY_FAILED_REASON,Constants.LOCAL_MSG_CALL_CANCEL);

                }else if(!MsgStatus._200100.equals(statusCode)){
                    redisSaveMap.put(RedisFields.CALL_HISTORY_FAILED_REASON,statusMsg);
                }

                if(StringTools.isNotempty(callState.getA_duration())) { //主叫时长

                    redisSaveMap.put(RedisFields.MAIN_CALL_LENGTH, callState.getA_duration());

                }

                if(StringTools.isNotempty(callState.getA_start_time())) { // 主叫开始时间可能没有这个时间
                    redisSaveMap.put(RedisFields.MAIN_CALL_START_TIME, DateUtils.stringFromString(callState.getA_start_time(), DateUtils.DATE_FORMAT_DATETIME_SSS));
                }

                if(StringTools.isNotempty(callState.getA_end_time())){ // 主叫结束时间可能没有这个时间
                    redisSaveMap.put(RedisFields.MAIN_CALL_END_TIME,DateUtils.stringFromString(callState.getA_end_time(),DateUtils.DATE_FORMAT_DATETIME_SSS));
                }

                if(StringTools.isNotempty(callState.getDuration())) { //被叫通话时长可能没有这个时间
                    redisSaveMap.put(RedisFields.TARGET_CALL_LENGTH, callState.getDuration());
                    redisSaveMap.put(RedisFields.CALL_HISTORY_RECORD_TIME_LENTH, callState.getA_duration());
                }

                if(StringTools.isNotempty(callState.getStart_time())) { //被叫开始时间可能没有这个时间
                    redisSaveMap.put(RedisFields.TARGET_CALL_START_TIME, DateUtils.stringFromString(callState.getStart_time(), DateUtils.DATE_FORMAT_DATETIME_SSS));
                }
                if(StringTools.isNotempty(callState.getEnd_time())){ //被叫结束时间可能没有这个时间
                    redisSaveMap.put(RedisFields.TARGET_CALL_END_TIME,DateUtils.stringFromString(callState.getEnd_time(),DateUtils.DATE_FORMAT_DATETIME_SSS));
                }

            }else{   //呼入
                //这里的状态有点错误，特殊处理下

                if(StringTools.isNotempty(callState.getStart_time())) { //可能没有这个时间
                    redisSaveMap.put(RedisFields.TARGET_CALL_START_TIME, DateUtils.stringFromString(callState.getStart_time(), DateUtils.DATE_FORMAT_DATETIME_SSS));
                }
                if(StringTools.isNotempty(callState.getEnd_time())){ //可能没有这个时间
                    redisSaveMap.put(RedisFields.TARGET_CALL_END_TIME,DateUtils.stringFromString(callState.getEnd_time(),DateUtils.DATE_FORMAT_DATETIME_SSS));
                }

                if(StringTools.isNotempty(callState.getDuration())) { //可能没有这个时间
                    redisSaveMap.put(RedisFields.CALL_HISTORY_RECORD_TIME_LENTH, callState.getDuration());
                    redisSaveMap.put(RedisFields.TARGET_CALL_LENGTH, callState.getDuration());

                }
            }
            //话务单回来也不需要发送到客户端
            msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE, Constants.WEB_SOCKET_MSG_TYPE_INVALID);

        }

        msgMap.put(Constants.WEB_SOCKET_JSON_KEY_TIME, nowDateStr);
        msgMap.put(Constants.WEB_SOCKET_JSON_KEY_SESSION_ID, callState.getOut_id());
        msgMap.put(Constants.WEB_SOCKET_JSON_KEY_DATA_ID, callHistoryMap.get(RedisFields.CALL_HISTORY_DATA_ID));
        msgMap.put(Constants.WEB_SOCKET_JSON_KEY_PAGE_FROM, callHistoryMap.get(RedisFields.CALL_HISTORY_PAGE_FROM));
        msgMap.put(Constants.WEB_SOCKET_JSON_KEY_MACHINE_FROM, callHistoryMap.get(RedisFields.CALL_HISTORY_MACHINE_FROM));

        resultMap.put(Constants.CALL_STATE_WORK_HANDLER_MAP_KEY_MSG,msgMap);
        resultMap.put(Constants.CALL_STATE_WORK_HANDLER_MAP_KEY_REDIS,redisSaveMap);

        return resultMap;
    }

    /**
     * 将呼叫消息推送到ES
     *
     * @param callHistoryMap
     */
    @Override
    protected void todoSaveCallRcord(Map<String, String> callHistoryMap) {
        try {
            String jsonStr = JSONObject.toJSONString(callHistoryMap);
            pushDataToEsTaskExecutor.execute(() -> {
                pushDataToEsBiz.pushCallHistoryToEs(callHistoryMap.get(RedisFields.CALL_HISTORY_SESSION_ID), jsonStr, RedisKey.CALL_HISTORY_RPIX + callHistoryMap.get(RedisFields.CALL_HISTORY_SESSION_ID));
            });
        }catch (Exception e){
            try {
                redisTemplate.opsForSet().add(RedisKey.PUSH_TO_ES_FAILED_HISTORY, callHistoryMap.get(RedisFields.CALL_HISTORY_SESSION_ID));
            }catch (Exception e1){
                logger.error("将推送ES 失败数据放入redis 失败！sessionId：{}",callHistoryMap.get(RedisFields.CALL_HISTORY_SESSION_ID),e1);
            }
            logger.error("====>推送Es 的线程池爆了",e);
        }

    }


    /**
     * 推送到websocket
     * @param callHistoryMap
     * @param resultMap
     * @throws Exception
     */
    @Override
    protected void pushStateToClient(Map<String, String> callHistoryMap, Map<String, Map<String, String>> resultMap) throws Exception {
        Map<String,String> msgMap = resultMap.get(Constants.CALL_STATE_WORK_HANDLER_MAP_KEY_MSG);
        String sessionId = callHistoryMap.get(Constants.WEB_SOCKET_JSON_KEY_SESSION_ID);

        //呼入暂时不推送数据到客户端
        if("1".equals(callHistoryMap.get(RedisFields.CALL_HISTORY_CALL_TYPE))
                || Constants.WEB_SOCKET_MSG_TYPE_INCOME.equals(msgMap.get(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE))) {
            logger.debug("INCOME msg,dont send to client");
            return;
        }
        if(Constants.WEB_SOCKET_MSG_TYPE_INVALID.equals(msgMap.get(Constants.WEB_SOCKET_JSON_KEY_MSG_TYPE))) {
            logger.debug("INVALID msg, dont send to client");
            return;
        }


        String json = JSONObject.toJSONString(msgMap);

        logger.info("推送状态:CallStateTaobaoWorkHandler pushStateToClient--->data:"+json);

        String rs = webSocketUtils.pushToClientBySessionId(sessionId, json);
        if(Constants.FAIL.equals(rs) || rs==null)
            logger.error("AliyunCallStateWorkHandler pushStateToClient--->rs:{},sessionId:{}",rs,sessionId);


    }


    /**
     * 推送爱家处理逻辑
     * @param callHistoryMap
     */
    @Override
    protected void pushRecordToBL(Map<String, String> callHistoryMap) {
        try {
            pushDataToBLBiz.callPushData(callHistoryMap);
        }catch (Exception e){
            logger.error("推送数据到保利失败data：{}",callHistoryMap.toString(),e);
            pushDataToBLBiz.setReids("record",callHistoryMap.get(RedisFields.CALL_HISTORY_SESSION_ID));
        }

    }
}
